/**
 * @file SystemTimer.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2024-10-25
 *
 * @copyright Copyright (c) 2024
 *
 */
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "SystemTimer.h"

#define TAG "SYSTEM_TIMER"
#define LOG_MESSAGE_DEBUG(TAG, ...)

/**
 * @brief system timer tick
 *
 */
static volatile uint32_t SystemTimerTick = 0;

/**
 * @brief system malloc function with error handling
 * 
 * @param size The size of memory to allocate
 * @return void* The pointer to the allocated memory
 */
static void *SystemTimerMalloc(size_t size)
{
	if (size == 0)
	{
		return NULL;
	}
    void *mem = malloc(size);
    if (mem == NULL)
    {
        LOG_MESSAGE_DEBUG(TAG, "Memory allocation failed!\n");
    }
    return mem;
}

/**
 * @brief system timer free function
 * 
 * @param mem The pointer to memory to free
 */
static void SystemTimerFree(void *mem)
{
    if (mem != NULL)
    {
        free(mem);
    }
}

/**
 * @brief system timer tickbase update
 *
 */
void SystemTimerTickUpdate(void)
{
	SystemTimerTick++;
}

/**
 * @brief system timer tickbase get
 *
 * @return uint32_t
 */
uint32_t SystemTimerTickGet(void)
{
	return SystemTimerTick;
}

/**
 * @brief system timer info print
 *
 * @param timer
 */
void SystemTimerPrint(const SystemTimer_t *timer)
{
	const SystemTimer_t *stimer = timer;

	for (; stimer; stimer = stimer->next)
	{
		LOG_MESSAGE_DEBUG(TAG, "id : %d,addr : %p", stimer->id, stimer);
	}
}

/**
 * @brief find system timer by timer id
 *
 * @param timer
 * @param id
 * @return SystemTimer_t*
 */
SystemTimer_t *SystemTimerFind(const SystemTimer_t *timer, uint32_t id)
{
	const SystemTimer_t *stimer = timer;

	for (; stimer; stimer = stimer->next)
	{
		if (stimer->id == id)
		{
			return (SystemTimer_t *)stimer;
		}
	}

	return NULL;
}


/**
 * @brief find system timer not use's idle id
 *
 * @param timer
 * @return uint32_t
 */
uint32_t SystemTimerFindIdleId(SystemTimer_t *timer)
{
	uint32_t idle_id = 0;
	const SystemTimer_t *stimer = timer;

	if (timer == NULL)
	{
		return idle_id;
	}

	for (; idle_id < MAX_TIMER_ID; idle_id++)
	{
		if (SystemTimerFind(stimer, idle_id) != NULL)
		{
			continue;
		}
		break;
	}

	return idle_id;
}

/**
 * @brief system timer create by head insert
 *
 * @param timer
 * @param param
 * @return SystemTimer_t*
 */
SystemTimer_t *SystemTimerHeadCreate(SystemTimer_t **timer, SystemTimerParam_t *param)
{
	const SystemTimer_t *stimer = *timer;
	SystemTimer_t *idle_timer = NULL;

	if (SystemTimerFind(stimer, param->id) != NULL)
	{
		LOG_MESSAGE_DEBUG(TAG, "System Timer Create Fail Id (%d) Conflict", param->id);
		return NULL;
	}

	idle_timer = (SystemTimer_t *)SystemTimerMalloc(sizeof(SystemTimer_t));
	if (idle_timer == NULL)
	{
		LOG_MESSAGE_DEBUG(TAG, "System Timer Create Fail Malloc Memery Fail");
		return NULL;
	}

	idle_timer->id = param->id;
	idle_timer->cb = param->cb;
	idle_timer->mode = param->mode;
	idle_timer->argv = param->argv;
	idle_timer->period = param->period;
	idle_timer->state = SYSTEM_TIMER_STOP;
	idle_timer->match = SystemTimerTickGet() + idle_timer->period;
	idle_timer->next = NULL;

	idle_timer->next = *timer;
	*timer = idle_timer;

	LOG_MESSAGE_DEBUG(TAG, "System Timer Create Id (%d) Success", param->id);

	return idle_timer;
}

/**
 * @brief system timer create by tail insert
 *
 * @param timer
 * @param param
 * @return SystemTimer_t*
 */
SystemTimer_t *SystemTimerTailCreate(SystemTimer_t **timer, SystemTimerParam_t *param)
{
	SystemTimer_t *stimer = *timer;
	SystemTimer_t *idle_timer = NULL;

	if (SystemTimerFind((const SystemTimer_t *)stimer, param->id) != NULL)
	{
		LOG_MESSAGE_DEBUG(TAG, "System Timer Create Fail Id (%d) Conflict", param->id);
		return NULL;
	}

	idle_timer = (SystemTimer_t *)SystemTimerMalloc(sizeof(SystemTimer_t));
	if (idle_timer == NULL)
	{
		LOG_MESSAGE_DEBUG(TAG, "System Timer Create Fail Malloc Memery Fail");
		return NULL;
	}

	idle_timer->id = param->id;
	idle_timer->cb = param->cb;
	idle_timer->mode = param->mode;
	idle_timer->argv = param->argv;
	idle_timer->period = param->period;
	idle_timer->state = SYSTEM_TIMER_STOP;
	idle_timer->match = SystemTimerTickGet() + idle_timer->period;
	idle_timer->next = NULL;

	if (stimer == NULL)
	{
		*timer = idle_timer;
		return idle_timer;
	}

	while (stimer->next != NULL)
	{
		stimer = stimer->next;
	}
	stimer->next = idle_timer;

	LOG_MESSAGE_DEBUG(TAG, "System Timer Create Id (%d) Success", param->id);

	return stimer;
}

/**
 * @brief system timer create
 *
 * @param timer
 * @param param
 * @return SystemTimer_t*
 */
SystemTimer_t *SystemTimerCreate(SystemTimer_t **timer, SystemTimerParam_t *param)
{
	// return SystemTimerTailCreate(timer,param);
	return SystemTimerHeadCreate(timer, param);
}

/**
 * @brief get system timer count
 *
 * @param timer
 * @return int
 */
int SystemTimerCountGet(const SystemTimer_t *timer)
{
	int count = 0;
	const SystemTimer_t *stimer = timer;

	for (; stimer; stimer = stimer->next)
	{
		count++;
	}

	return count;
}

/**
 * @brief system timer destory head node
 *
 * @param timer
 */
void SystemTimerHeadDestory(SystemTimer_t **timer)
{
	SystemTimer_t *delete_timer = *timer;

	if (delete_timer)
	{
		*timer = delete_timer->next;
		LOG_MESSAGE_DEBUG(TAG, "Destory Id (%d)", delete_timer->id);
		SystemTimerFree(delete_timer);
	}
}

/**
 * @brief system timer destory node
 *
 * @param timer
 * @param delete_timer
 */
void SystemTimerDestory(SystemTimer_t **timer, SystemTimer_t *delete_timer)
{
	if (delete_timer == NULL)
	{
		return;
	}
	for (SystemTimer_t **cur = timer; *cur;)
	{
		SystemTimer_t *entry = *cur;
		if (entry == delete_timer)
		{
			*cur = entry->next;
			LOG_MESSAGE_DEBUG(TAG, "Destory Id (%d)", entry->id);
			SystemTimerFree(entry);
			return;
		}
		else
		{
			cur = &entry->next;
		}
	}
}

/**
 * @brief system timer destory tail node
 *
 * @param timer
 */
void SystemTimerTailDestory(SystemTimer_t **timer)
{
	SystemTimer_t *delete_timer = *timer;

	if (delete_timer == NULL)
	{
		return;
	}

	while (delete_timer && delete_timer->next != NULL)
	{
		delete_timer = delete_timer->next;
	}
	SystemTimerDestory(timer, delete_timer);
}

/**
 * @brief system timer destory timer linklist
 *
 * @param timer
 */
void SystemTimerDestoryLinkList(SystemTimer_t **timer)
{
	int count = 0;
	const SystemTimer_t *stimer = *timer;

	count = SystemTimerCountGet(stimer);

	for (int i = 0; i < count; i++)
	{
		SystemTimerHeadDestory(timer);
	}
}

/**
 * @brief system timer recurse
 * 
 * @param timer 
 */
void SystemTimerNodeDestory(SystemTimer_t *timer)
{
	SystemTimer_t *next_timer = NULL;

	while (timer != NULL)
	{
		next_timer = timer->next;
		SystemTimerFree(timer);
		timer = next_timer;
	} 
}

/**
 * @brief system timer destory by recurse
 * 
 * @param timer 
 */
void SystemTimerDestoryLinkListRecurse(SystemTimer_t **timer)
{
	SystemTimer_t *dTimer = *timer;
	SystemTimerNodeDestory(dTimer);
	*timer = NULL;
}


/**
 * @brief system timer destory has used finsh oneshort timer
 *
 * @param timer
 */
static void SystemTimerUseEndDestory(SystemTimer_t **timer, SystemTimer_t *destory)
{
	SystemTimerDestory(timer, destory);
}

/**
 * @brief system timer start
 *
 * @param timer
 */
void SystemTimerStart(SystemTimer_t *timer)
{
	if (timer)
	{
		timer->state = SYSTEM_TIMER_RUNNING;
	}
}

/**
 * @brief system timer stop
 *
 * @param timer
 */
void SystemTimerStop(SystemTimer_t *timer)
{
	if (timer)
	{
		timer->state = SYSTEM_TIMER_STOP;
	}
}

/**
 * @brief set system timer cur use status is destory status
 *
 * @param timer
 */
void SystemTimerUseEnd(SystemTimer_t *timer)
{
	if (timer)
	{
		timer->state = SYSTEM_TIMER_DESTORY;
	}
}

/**
 * @brief start system timer linklist
 *
 * @param timer
 */
void SystemTimerStartWhole(SystemTimer_t *timer)
{
	SystemTimer_t *stimer = timer;

	for (; stimer; stimer = stimer->next)
	{
		SystemTimerStart(stimer);
	}
}

/**
 * @brief stop system timer linklist
 *
 * @param timer
 */
void SystemTimerStopWhole(SystemTimer_t *timer)
{
	SystemTimer_t *stimer = timer;

	for (; stimer; stimer = stimer->next)
	{
		SystemTimerStop(stimer);
	}
}

/**
 * @brief update system timer execute period
 *
 * @param timer
 */
void SystemTimerUpdateValue(SystemTimer_t *timer)
{
	if (timer)
	{
		timer->match = SystemTimerTickGet() + timer->period;
	}
}


/**
 * @brief timer handle execute action
 *
 * @param timer
 */
void SystemTimerHandle(SystemTimer_t **timer)
{
	SystemTimer_t *stimer = *timer;
	static SystemTimer_t *destroy_timer_list = NULL;
	for (; stimer; stimer = stimer->next)
	{
		switch (stimer->state)
		{
		case SYSTEM_TIMER_STOP:
			break;
		case SYSTEM_TIMER_RUNNING:
			if (SystemTimerTickGet() >= stimer->match)
			{
				stimer->state = SYSTEM_TIMER_TIMEOUT;
				if (stimer->cb)
				{
					stimer->cb(stimer->argv);
				}
			}
			break;
		case SYSTEM_TIMER_TIMEOUT:
			if (stimer->mode == TIMER_ONESHOT_MODE)
			{
				stimer->state = SYSTEM_TIMER_DESTORY;
			}
			else
			{
				stimer->state = SYSTEM_TIMER_RUNNING;
				stimer->match = SystemTimerTickGet() + stimer->period;
			}
			break;
		case SYSTEM_TIMER_DESTORY:
			if (destroy_timer_list == NULL){
				destroy_timer_list = stimer;
			}
			break;
		default:
			break;
		}
	}
	if (destroy_timer_list){
		SystemTimerUseEndDestory(timer, destroy_timer_list);
		destroy_timer_list = NULL;
	}
	
}
